"""
GitCode MCP服务器，提供GitCode API功能的MCP接口
"""
import os
import json
import logging
import sys
from typing import Dict, List, Optional, Any, Tuple

from mcp.server.fastmcp import FastMCP
import mcp.types as types
from dotenv import load_dotenv

from gitcode_mcp.api.base.client import GitCodeAPI

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout),  # 明确输出到标准输出
        logging.FileHandler("gitcode_mcp.log")
    ]
)
logger = logging.getLogger("gitcode_mcp")
logger.info("GitCode MCP服务器模块初始化...")

# 加载环境变量
load_dotenv()
logger.info("环境变量已加载")

# 创建FastMCP服务器实例
mcp = FastMCP("GitCode MCP服务器")
logger.info(f"FastMCP实例已创建，名称: GitCode MCP服务器")
api_client: Optional[GitCodeAPI] = None


# 初始化API客户端
def init_api_client():
    """初始化API客户端"""
    global api_client
    if api_client is not None:
        return api_client
        
    token = os.environ.get("GITCODE_TOKEN")
    if not token:
        logger.warning("未设置GITCODE_TOKEN环境变量，API访问可能受限")
    
    api_client = GitCodeAPI(token)
    logger.info("GitCode API客户端已初始化")
    return api_client


# 辅助函数
async def safe_api_call(func, *args, **kwargs):
    """安全调用API，统一处理错误和日志"""
    client = init_api_client()
    
    try:
        return await func(*args, **kwargs)
    except Exception as e:
        error_message = f"API调用失败: {func.__name__}({args}, {kwargs}) - {str(e)}"
        logger.error(error_message)
        raise ValueError(error_message) from e


# === 工具 ===

@mcp.tool()
async def list_repositories() -> str:
    """列出当前用户的仓库"""
    client = init_api_client()
    repos = await safe_api_call(client.repos.list_user_repos)
    return json.dumps(repos, ensure_ascii=False)


@mcp.tool()
async def get_repository(owner: str, repo: str) -> str:
    """获取特定仓库的详细信息"""
    client = init_api_client()
    repo_info = await safe_api_call(client.repos.get_repo, owner=owner, repo=repo)
    return json.dumps(repo_info, ensure_ascii=False)


@mcp.tool()
async def create_repository(name: str, description: str = "", private: bool = False) -> str:
    """创建新仓库"""
    client = init_api_client()
    repo = await safe_api_call(client.repos.create_repo, name=name, description=description, private=private)
    return json.dumps(repo, ensure_ascii=False)


@mcp.tool()
async def list_branches(owner: str, repo: str) -> str:
    """列出仓库的分支"""
    client = init_api_client()
    branches = await safe_api_call(client.branches.list_branches, owner=owner, repo=repo)
    return json.dumps(branches, ensure_ascii=False)


@mcp.tool()
async def get_branch(owner: str, repo: str, branch: str) -> str:
    """获取特定分支的详细信息"""
    client = init_api_client()
    branch_info = await safe_api_call(client.branches.get_branch, owner=owner, repo=repo, branch=branch)
    return json.dumps(branch_info, ensure_ascii=False)


@mcp.tool()
async def create_branch(owner: str, repo: str, branch: str, ref: str) -> str:
    """创建新分支"""
    client = init_api_client()
    branch_info = await safe_api_call(client.branches.create_branch, owner=owner, repo=repo, branch=branch, ref=ref)
    return json.dumps(branch_info, ensure_ascii=False)


@mcp.tool()
async def list_issues(owner: str, repo: str) -> str:
    """列出仓库的Issues"""
    client = init_api_client()
    issues = await safe_api_call(client.issues.list_issues, owner=owner, repo=repo)
    return json.dumps(issues, ensure_ascii=False)


@mcp.tool()
async def get_issue(owner: str, repo: str, issue_number: int) -> str:
    """获取特定Issue的详细信息"""
    client = init_api_client()
    issue = await safe_api_call(client.issues.get_issue, owner=owner, repo=repo, issue_number=issue_number)
    return json.dumps(issue, ensure_ascii=False)


@mcp.tool()
async def create_issue(owner: str, repo: str, title: str, body: str = "") -> str:
    """创建新Issue"""
    client = init_api_client()
    issue = await safe_api_call(client.issues.create_issue, owner=owner, repo=repo, title=title, body=body)
    return json.dumps(issue, ensure_ascii=False)


@mcp.tool()
async def list_pull_requests(owner: str, repo: str) -> str:
    """列出仓库的Pull Requests"""
    client = init_api_client()
    prs = await safe_api_call(client.pulls.list_pull_requests, owner=owner, repo=repo)
    return json.dumps(prs, ensure_ascii=False)


@mcp.tool()
async def get_pull_request(owner: str, repo: str, pull_number: int) -> str:
    """获取特定Pull Request的详细信息"""
    client = init_api_client()
    pr = await safe_api_call(client.pulls.get_pull_request, owner=owner, repo=repo, pull_number=pull_number)
    return json.dumps(pr, ensure_ascii=False)


@mcp.tool()
async def create_pull_request(owner: str, repo: str, title: str, head: str, base: str, body: str = "") -> str:
    """创建新Pull Request"""
    client = init_api_client()
    pr = await safe_api_call(
        client.pulls.create_pull_request, 
        owner=owner, 
        repo=repo, 
        title=title, 
        head=head, 
        base=base, 
        body=body
    )
    return json.dumps(pr, ensure_ascii=False)


@mcp.tool()
async def search_code(query: str) -> str:
    """搜索代码"""
    client = init_api_client()
    results = await safe_api_call(client.search.search_code, query=query)
    return json.dumps(results, ensure_ascii=False)


@mcp.tool()
async def search_repositories(query: str) -> str:
    """搜索仓库"""
    client = init_api_client()
    results = await safe_api_call(client.search.search_repositories, query=query)
    return json.dumps(results, ensure_ascii=False)


@mcp.tool()
async def search_issues(query: str) -> str:
    """搜索Issues"""
    client = init_api_client()
    results = await safe_api_call(client.search.search_issues, query=query)
    return json.dumps(results, ensure_ascii=False)


@mcp.tool()
async def search_users(query: str) -> str:
    """搜索用户"""
    client = init_api_client()
    results = await safe_api_call(client.search.search_users, query=query)
    return json.dumps(results, ensure_ascii=False)


# === 资源 ===

@mcp.resource("repo://{owner}/{name}")
async def get_repository_resource(owner: str, name: str) -> str:
    """获取仓库资源"""
    client = init_api_client()
    
    try:
        repo_data = await safe_api_call(client.repos.get_repo, owner=owner, repo=name)
        formatted_content = (
            f"# {repo_data.get('name')}\n\n"
            f"{repo_data.get('description', '')}\n\n"
            f"- 所有者: {owner}\n"
            f"- 星标数: {repo_data.get('stargazers_count', 0)}\n"
            f"- Fork数: {repo_data.get('forks_count', 0)}\n"
            f"- 默认分支: {repo_data.get('default_branch', 'main')}\n"
            f"- 创建时间: {repo_data.get('created_at', '')}\n"
            f"- 最后更新: {repo_data.get('updated_at', '')}\n"
        )
        
        return formatted_content
    except Exception as e:
        logger.error(f"读取资源时出错: {owner}/{name} - {e}")
        return f"Error: {str(e)}"


# === 提示模板 ===

@mcp.prompt()
def create_issue_prompt(owner: str, repo: str, title: str, body: str = "") -> str:
    """创建Issue的提示模板"""
    return f"""在 {owner}/{repo} 仓库中创建一个新Issue：

标题：{title}

内容：{body}"""


@mcp.prompt()
def create_pull_request_prompt(owner: str, repo: str, title: str, head: str, base: str, body: str = "") -> str:
    """创建Pull Request的提示模板"""
    return f"""在 {owner}/{repo} 仓库中创建一个新Pull Request：

标题：{title}

从分支 {head} 到 {base}

描述：{body}"""


@mcp.prompt()
def search_code_prompt(query: str) -> str:
    """搜索代码的提示模板"""
    return f"""搜索代码片段：{query}"""


def main():
    """主函数，启动MCP服务器"""
    
    def run_server():
        logger.info("准备启动服务器...")
        try:
            # 确保API客户端已初始化
            init_api_client()
            logger.info("API客户端已初始化")
            
            # 运行服务器
            logger.info("MCP服务器开始运行")
            # FastMCP使用run方法而不是listen方法
            mcp.run()
            logger.info("MCP服务器已关闭")
        except Exception as e:
            logger.error(f"服务器运行错误: {e}", exc_info=True)
    
    logger.info("正在启动GitCode MCP服务器...")
    try:
        # FastMCP的run方法是同步的，不需要asyncio.run
        run_server()
    except KeyboardInterrupt:
        logger.info("服务器被手动停止")
    except Exception as e:
        logger.error(f"服务器启动失败: {e}", exc_info=True)


if __name__ == "__main__":
    main()
